using System.Collections.Generic;
using TestCases.CompareAssert.Core.Comparers.Interfaces;
using TestCases.CompareAssert.Core.Compositions;
using TestCases.CompareAssert.Core.Compositions.Interfaces;
using TestCases.CompareAssert.Core.Interfaces;

namespace TestCases.CompareAssert.Core.Comparers.Composite
{
    public class CompositeComparer : IObjectComparer, ICompositionComparer<IObjectComparer, IResultProvider>
    {
        public const string IdentifiableName = "CompositeComparer";


        private readonly IEnumerable<IObjectComparer> _comparers;
        private readonly ICompositionStrategy<IObjectComparer, IResultProvider> _strategy;

        public CompositeComparer(IEnumerable<IObjectComparer> comparers) : this(comparers, CompositionType.All)
        {
        }

        public CompositeComparer(IEnumerable<IObjectComparer> comparers, CompositionType compositionType) :
            this(comparers, compositionType.CreateStrategy<IObjectComparer, IResultProvider>())
        {
        }
        
        public CompositeComparer(
            IEnumerable<IObjectComparer> comparers, 
            ICompositionStrategy<IObjectComparer, IResultProvider> strategy)
        {
            _comparers = comparers;
            _strategy = strategy;
        }

        public string Name
        {
            get { return IdentifiableName; }
        }

        public IResultBuilder Compare(ICompareContext context)
        {
            return _strategy.Execute(this, _comparers, context);
        }
                
        public IResultProvider CompareBy(IObjectComparer item, ICompareContext context)
        {
            return item.Compare(context);
        }

        public IResultBuilder ComposeItemResults(CompareStatus status, ICompareContext context, IList<IResultProvider> children)
        {
            return this.IsStatusResult(status, context, children);
        }

        public static CompositeComparer Compose(CompositionType type, params IObjectComparer[] comparers)
        {
            return new CompositeComparer(comparers, type);
        }

        public static CompositeComparer All(params IObjectComparer[] comparers)
        {
            return new CompositeComparer(comparers, CompositionType.All);
        }

        public static CompositeComparer Any(params IObjectComparer[] comparers)
        {
            return new CompositeComparer(comparers, CompositionType.Any);
        }
        
        public static CompositeComparer Single(params IObjectComparer[] comparers)
        {
            return new CompositeComparer(comparers, CompositionType.Single);
        }

    }
}